package com.powerfl.frm.taf{
	
	import flash.display.*;
	import flash.events.*;
	import flash.media.*;
	import flash.net.*;
	import flash.system.*;
	import flash.utils.*;
	
	final internal class TAFloader{
		
		static internal function LOAD( $type:String, $path:String, $data:TAFparam, $end:Function ):void{
			var i:int, j:int,
				embedPath:Array, embed:TAFembed, embedEnd:Function, data:Object,
				request:URLRequest, variable:URLVariables, loader:TAFloader, filedata:ByteArray, boundary:String, key:String, str:String;
			
			if( $path.substr( 0, 8 ) === 'embed://' ){
				embedPath = $path.substr( 8 ).split( '/' ); 
				embed = TAF.SELF.tdata( embedPath[0] + '@EMBED' );
				embedEnd = function():void{
					$end( TAF.SELF.tdata( embedPath[0] + '@EMBED' ).getKey( embedPath[1] ) );
				}
				if( embed ){
					embedEnd();
				}else{
					TAF.SELF.addTree( '@DATA', embedPath[0] + '@EMBED', 'embed', new TAFembed, null );
					TAF.SELF.tdata( embedPath[0] ).init( TAF.SELF.tdata( embedPath[0] ), embedEnd );
				}
				return;
			}
			
			loader = TAF.SELF.poolPullLoader();
			loader._type = $type;
			loader._end = $end;
			if( loader._request === null){
				loader._request = new URLRequest;
			}
			request = loader._request;
			request.url = $path;
			
			if( $data ){
				data = $data.param;
			}
			if( data){
				if( data.get is Object ){
					variable = new URLVariables;
					for( key in data.get ){
						variable[key] = data.get[key];
					}
					request.url = $path + '?' + variable.toString();
				}
				if( data.file ){
					request.method = URLRequestMethod.POST;
					boundary = '';
					for( i = 0 ; i < 0x20 ; ++i ){
						boundary += String.fromCharCode( int( 97 + Math.random() * 25 ) );
					}
					request.contentType = 'multipart/form-data, boundary='+boundary;
					
					filedata = new ByteArray;
					filedata.endian = Endian.BIG_ENDIAN;
					
					if( data.post ){
						for( key in data.post ){
							filedata.writeShort( 0x2d2d );
							for( i = 0 ; i < boundary.length; ++i ){
								filedata.writeByte( boundary.charCodeAt( i ) );
							}
							filedata.writeShort( 0x0d0a );
							str = 'Content-Disposition: form-data; name="' + key + '"';
							for( i = 0 ; i < str.length; ++i ){
								filedata.writeByte( str.charCodeAt( i ) );
							}
							filedata.writeShort( 0x0d0a );
							filedata.writeShort( 0x0d0a );
							filedata.writeUTFBytes( data.post[key] );
							filedata.writeShort( 0x0d0a );
						}
					}
					for( key in data.file ){
						filedata.writeShort( 0x2d2d );
						for( i = 0 ; i < boundary.length; ++i ){
							filedata.writeByte( boundary.charCodeAt( i ) );
						}
						filedata.writeShort( 0x0d0a );
						str = 'Content-Disposition: form-data; name="' + key + '"; filename="' + key + '.jpg"';
						for( i = 0 ; i < str.length; ++i ){
							filedata.writeByte( str.charCodeAt( i ) );
						}
						filedata.writeShort( 0x0d0a );
						str = 'Content-Type: application/octet-stream';
						for( i = 0 ; i < str.length; ++i ){
							filedata.writeByte( str.charCodeAt( i ) );
						}
						filedata.writeShort( 0x0d0a );
						filedata.writeShort( 0x0d0a );
						filedata.writeBytes( data.file[key], 0, data.file[key].length );
						filedata.writeShort( 0x0d0a );
					}
					filedata.writeShort( 0x2d2d );
					for( i = 0 ; i < boundary.length; ++i ){
						filedata.writeByte( boundary.charCodeAt( i ) );
					}
					filedata.writeShort( 0x2d2d );
					filedata.writeShort( 0x0d0a );
					request.data = filedata;
				}else if( data.post is Object ){
					request.method = URLRequestMethod.POST;
					variable = new URLVariables;
					for( key in data.post ){
						variable[key] = data.post[key];
					}
					request.data = variable;
				}
			}
			
			switch( $type){
			case'image':case'swf':
				loader._loader = new Loader;
				loader._monitor = loader._loader.contentLoaderInfo;
				if( data && data.ad ){
					loader._ad = data.ad;
				}else{
					loader._ad = new ApplicationDomain;
				}
				break;
			case'sound':
				loader._loader = new Sound;
				loader._monitor = loader._loader;
				break;
			case'byte':case'ini':case'text':case'xml':
				loader._loader = new URLLoader;
				loader._monitor = loader._loader;
				loader._loader.dataFormat = URLLoaderDataFormat.BINARY;
				loader._loader.data = null;
				break;
			}
			if( data && data.progress ){
				loader._progress = data.progress; 
			}
			loader.load();
		}
		
		private var _type:String;
		private var _request:URLRequest;
		private var _ad:ApplicationDomain;
		private var _end:Function;
		private var _progress:Function;
		
		private var _loader:*;
		private var _context:LoaderContext;
		private var _monitor:*;
		
		private var _retry:uint;
		private var _timeOut:uint;
		private var _limitTime:uint;
		private var _tryCount:uint;
		
		private var _isStart:uint;
		private var _isOpen:uint;
		private var _progressed:String;
		private var _isLoading:Boolean;
		private var _isComplete:uint;
		private var _httpStatus:int;
		private var _ioError:String;
		private var _securityError:String;
		
		public function TAFloader(){}
		internal function collect():TAFloader{
			TAF.SELF.plugUnbindRunner( ENTER_FRAME, 5 );
			
			_monitor.removeEventListener( Event.COMPLETE, COMPLETE );
			_monitor.removeEventListener( ProgressEvent.PROGRESS, PROGRESS );
			_monitor.removeEventListener( Event.OPEN, OPEN );
			_monitor.removeEventListener( HTTPStatusEvent.HTTP_STATUS, HTTP_STATUS );
			_monitor.removeEventListener( SecurityErrorEvent.SECURITY_ERROR, SECURITY_ERROR );
			_monitor.removeEventListener( IOErrorEvent.IO_ERROR, IO_ERROR );
			
			_request.url = '';
			_request.data = null;
			_request.contentType = 'application/x-www-form-urlencoded';
			_request.method = URLRequestMethod.GET;
			
			return this;
		}
		private function load():void{
			var temp:String;
			_monitor.addEventListener( Event.COMPLETE, COMPLETE );
			_monitor.addEventListener( ProgressEvent.PROGRESS, PROGRESS );
			_monitor.addEventListener( Event.OPEN, OPEN );
			_monitor.addEventListener( HTTPStatusEvent.HTTP_STATUS, HTTP_STATUS );
			_monitor.addEventListener( SecurityErrorEvent.SECURITY_ERROR, SECURITY_ERROR );
			_monitor.addEventListener( IOErrorEvent.IO_ERROR, IO_ERROR );
			TAF.SELF.plugBindRunner( ENTER_FRAME, 5 );
			if( _loader is Loader ){
				_context = new LoaderContext;
				_context.applicationDomain = _ad;
				if( Security.sandboxType === Security.REMOTE ){
					_context.checkPolicyFile = true;
					if( _request.url.indexOf( 'http://' ) === -1 ){
						_context.checkPolicyFile = false;
						_context.securityDomain = SecurityDomain.currentDomain;
					}else{
						_context.checkPolicyFile = true;
					}
				}
			}
			_tryCount = 0;
			init();
			loadRun();
		}
		private function init():void{
			_httpStatus = _isComplete = _isOpen = _isStart = 0;
			_isLoading = false;
			_progressed = _securityError = _ioError = '';
		}
		private function loadRun():void{
			if( _isStart ){
				_loader.close();
				init();
			}
			++_tryCount;
			_isStart = getTimer();
			_limitTime = getTimer() + 5000;
			if( _loader is Loader ){
				_loader.load( _request, _context );
			}else{
				_loader.load( _request );
			}
		}
		private function error():void{
			_loader.close();
			TAF.SELF.poolCollectLoader( this );
			trace(
				'로드 에러레포트---------------\n' +
				'재시도수: '+_tryCount+'\n'+
				'로드URL: '+_request.url+'\n'+
				'상태코드: '+_httpStatus+'\n'+
				'입출에러: '+_ioError+'\n'+
				'보안에러: '+_securityError+'\n'+
				'로드시작: '+_isStart+'\n'+
				'로드오픈: '+_isOpen+'\n'+
				'로드진행: '+_progress+'\n'+
				'로드완료: '+_isStart
			);
		}
		private function ENTER_FRAME():void{
			if( _isStart && _isLoading === false && _isComplete === 0 && getTimer() > _limitTime ){
				if( _tryCount === _retry ){
					error();
				}else{
					loadRun();
				}
			} 
		}
		private function OPEN( $e:Event ):void{
			_isOpen = getTimer();
		}
		private function PROGRESS( $e:ProgressEvent ):void{
			var loaded:int, total:int;
			loaded = $e.target.bytesLoaded;
			total = $e.target.bytesTotal;
			if( total > 0 )if( loaded > 0 ){
				_isLoading = true;
				_progressed = loaded.toString() + ' / ' + total.toString();
				if( _progress === null ){}else{
					_progress( loaded, total );
				}
			}
		}
		private function HTTP_STATUS( $e:HTTPStatusEvent ):void{
			_httpStatus = $e.status;
			switch( _httpStatus.toString().charAt(0) ){
			case'5':case'4': error(); break;
			}
		}
		private function SECURITY_ERROR( $e:SecurityErrorEvent ):void{
			_securityError = $e.text;
			error();
		}
		private function IO_ERROR( $e:IOErrorEvent ):void{
			_ioError = $e.text;
			error();
		}
		private function COMPLETE( $e:Event ):void{
			var data:*, temp:*, key:*;
			_isComplete = getTimer();
			switch( _type ){
			case'image':
				data = _loader.content.bitmapData.clone();
				_loader.content.bitmapData.dispose();
				break;
			case'swf':
				data = _loader.content;
				break;
			case'sound':
				data = _loader;
				break;
			case'byte':
				data = _loader.data;
				break;
			case'xml':
				data = new XML( readEncoding( _loader.data ) );
				break;
			case'ini':
				data = TAF.INI( readEncoding( _loader.data ) );
				break;
			case'text':
				data = readEncoding( _loader.data );
				break;
			}
			TAF.SELF.poolCollectLoader( this );
			_end( data );
		}
		private function readEncoding( $data:ByteArray ):String{
			var ansiStr:String, unicodeStr:String;
			switch( $data[0] ){
			case 0xEF://UTF-8 with BOM
				if( $data[1] === 0xBB && $data[2] === 0xBF){
					return $data.toString();
				}
				break;
			case 0xFE://UTF-16 Big Endian
				if( $data[1] === 0xFF ){
					return $data.toString();
				}
				break;
			case 0xFF://UTF-16 Little Endian, UTF-32 Little Endian
				if( $data[1] === 0xFE){
					return $data.toString();
				}
				break;
			case 0x0://UTF-32 Big Endian
				if( $data[1] === 0x0 && $data[2] === 0xFE && $data[3] === 0xFF){
					return $data.toString();
				}
			}
			ansiStr = $data.readMultiByte( $data.length, "ANSI");
			unicodeStr = $data.toString();
			if( ansiStr.length < unicodeStr.length ){
				return ansiStr;
			}else{
				return unicodeStr;
			}			
		}
	}
}